package controllers

import java.util.Date

import DB._
import common.Tool._
import common._
import org.apache.http.entity.{ContentType, StringEntity}
import play.api.Logger
import tools.{WeiXin, NetTool}

import scala.collection.mutable.{Map => mutableMap}
import scala.concurrent.Future
import scala.util.Random
import scala.util.parsing.json.{JSON => SJSON}
import common.JedisCacheKeys._

/**
  * Created by 林 on 14-4-10.
  */
object WeixinController extends BaseController {
  def weixinValidation(app: String) = JsAction {
    implicit request =>
      Ok(getQuery("echostr")(request)(0))
  }

  def weixinPay = getSettingCacheObject("weixinAppid", "weixinSecret", "wxmchId", "payKey")(list => new WeiXin(list(0), list(1), list(2), list(3)))

  def getWeiXin(app: String) = {
    cacheMethod(APP_TABLE_CACHE_KEY + "_" + app, 1200) {
      val weixinapp = new App().queryById(app).get
      new WeiXin(weixinapp.appid, weixinapp.appsecr, "", "")
    }
  }

  def help(app: String,uid:String) = (setting("pushMsg"), baseUrl + s"/m/index?app=${app}&uid=${uid.encrypt()}&t=" + randomStr(15), setting("imgUrl")) :: Nil

  //微信接口逻辑
  def weixinIndex(app: String) = JsAction.async { implicit request =>
    val body = request.body.asXml
    val data = if (body.isDefined) body.get.toString() else ""
    val realData = new String(data.getBytes("iso-8859-1"))
    Logger.debug(realData)
    val ret = scala.xml.XML.loadString(realData)
    val recv = ret.child.map {
      i => (i.label) -> (i.text)
    }.toMap
    Future {
      Logger.debug(recv.toJson)
      val reContext = if (List("location", "voice", "video").contains(recv("MsgType")))
        ("text", recv("MsgType") + ":对不起,暂不支持该操作 \r\n", Map.empty[String, String])
      else {
        try {
          wxMessageParse(recv, app)
        } catch {
          case ve: VenusException => ("text", ve.getMessage, Map.empty[String, String])
          case t: Throwable =>
            t.printStackTrace()
            ("text", "暂时无法提供服务:" + t.getMessage, Map.empty[String, String])
        }
      }
      //返回模板
      val textTpl = if (reContext._1 == "text") {
        if(isEmpty(reContext._2)) "success" else
        s"""<xml>
                <ToUserName><![CDATA[${recv("FromUserName")}]]></ToUserName>
                <FromUserName><![CDATA[${recv("ToUserName")}]]></FromUserName>
                <CreateTime>${recv("CreateTime")}</CreateTime>
                <MsgType><![CDATA[text]]></MsgType>
                <Content><![CDATA[${reContext._2}]]></Content>
                <FuncFlag>0</FuncFlag>
                </xml>"""
      } else {
        val list = reContext._3("list").asInstanceOf[List[Tuple3[String, String, String]]]
        s"""<xml>
               <ToUserName><![CDATA[${recv("FromUserName")}]]></ToUserName>
               <FromUserName><![CDATA[${recv("ToUserName")}]]></FromUserName>
               <CreateTime>${recv("CreateTime")}</CreateTime>
               <MsgType><![CDATA[news]]></MsgType>
               <ArticleCount>${list.size}</ArticleCount>
               <Articles>
               ${
          list.map { v =>
            s"""               <item>
                      <Title><![CDATA[${v._1}]]></Title>
                      <Url><![CDATA[${v._2}]]></Url>
                      <PicUrl><![CDATA[${v._3}]]></PicUrl>
                      </item>"""
          }
        }

               </Articles>
               </xml>"""
      }
      Logger.debug(textTpl)
      Ok(textTpl)
    }
  }

  /**
    * 解析微信消息
    *
    * @param m
    * @return
    */
  def wxMessageParse(m: Map[String, String], app: String): (String, String, Map[String, AnyRef]) = {
    val wxId = m("FromUserName")
    val msgType = m("MsgType")
    val unid = JedisTool.useJedis(_.hget(WEIXIN_ID_CACHE_KEY+app, wxId).getOrElse(""))
    msgType match {
      case "event" => m("Event") match {
        case "TEMPLATESENDJOBFINISH" => ("text", "", Map.empty[String, String])
        case "SCAN" => val unid=insertWeiXinToken(wxId, app)
          if(isEmpty(unid)){
            ("text", "当前领取红包人数过多,请取消关注,重新关注!", Map.empty[String, String])
          }else{
            ("news", "", Map("list" -> help(app,unid)))
          }
        case "subscribe" => val unid = insertWeiXinToken(wxId, app)
          if(isEmpty(unid)){
            ("text", "当前领取红包人数过多,请取消关注,重新关注!", Map.empty[String, String])
          }else{
            ("news", "", Map("list" -> help(app,unid)))
          }
        case "unsubscribe" =>
          ("text", "", Map.empty[String, String])
        case "VIEW" => ("text", "", Map.empty[String, String])
        case "CLICK" => ("text", "服务未开通", Map.empty[String, String])
      }
      case "image" => ("text", "暂不支持该操作", Map.empty[String, String])
      case "text" => dealContent(m("Content"), unid, wxId, app)
    }
  }


  /**
    * 写入微信token
    *
    * @param wxid
    * @return
    */
  def insertWeiXinToken(wxid: String, app: String) = {
    val userconnect = new UserConnect().query("token=?", wxid)
    if (userconnect.isEmpty) {
      val ui = getWeiXin(app).userInfo(wxid)
      val (icon, name) = getUserBaseInfo(ui)
      val unid = ui.getOrElse("unionid", "")
      if (!unid.isEmpty) {
        JedisTool.useJedis(_.hset(WEIXIN_ID_CACHE_KEY+app, wxid, unid))
        new UserConnect(uuid, name, app.toInt, icon, unid, false, wxid, ui.toJson, new Date).insertWithId()
        val user = new User().queryById(unid)
        if (user.isEmpty) {
          new User(unid, name, icon, "", new Date).insertWithId()
        }
        else if (!isEmpty(user.get.payToken)) {
          onlyTask("only_" + unid) {
            new UserConnect().query("uid=?", unid).filter(!_.hasSend).foreach { app =>
              if(sendredpack(unid, user.get.payToken, app.appid)) {
                new UserConnect(app.id, hasSend = true).update("id", "hasSend")
              }
            }
          }
        }
        unid
      }else ""
    } else {
      userconnect.head.uid
    }
  }

  /**
    * 文本消息处理
    *
    * @param text
    * @param uid
    * @param token
    * @return
    */
  def dealContent(text: String, uid: String, token: String, app: String) = {
    if (text == "信息") {
      run {
        Thread.sleep(100)
        getWeiXin(app).sendMsg(token, s"信息,uid:${uid},token:${token},app:${app}")
        getWeiXin(app).sendMsg(token, s"${getWeiXin(app).userInfo(token).toString()}")
      }
      ("text", "", Map.empty[String, String])
    } else if (text == "你妹的红包啊") {
      if (isEmpty(uid)) {
        val unid=insertWeiXinToken(token, app)
        ("news", "", Map("list" -> help(app,unid)))
      } else {
        val user = new User().queryById(uid)
        uid.synchronized {
          if (user.isDefined && !isEmpty(user.get.payToken)) {
            sendredpack(uid, user.get.payToken, app.toInt)
            ("text", "发放成功", Map.empty[String, String])
          } else {
            ("news", "", Map("list" -> help(app, uid)))
          }
        }
      }
    } else if (text == "更新") {
      val uc=new UserConnect().query(s"token=? and appid=$app", token)
      //判断是否有usertoken
      if (uc.isEmpty|| isEmpty(uc.head.uid)) {
        val ui = getWeiXin(app).userInfo(token)
        val unid = ui.getOrElse("unionid", "")
        if (!unid.isEmpty) {
          val (icon: String, name: String) = getUserBaseInfo(ui)
          JedisTool.useJedis(_.hset(WEIXIN_ID_CACHE_KEY+app, token, unid))
          if(uc.isEmpty){
            new UserConnect(uuid, name, app.toInt, icon, unid, false, token, ui.toJson, new Date).insertWithId()
            ("text", "插入连接信息成功:" + name, Map.empty[String, String])
          }else
          {
            new UserConnect(uc.head.id, name, app.toInt, icon, unid, uc.head.hasSend, token, ui.toJson, new Date).update("id","name","icon","appid","uid")
            ("text", "更新连接信息成功:" + name, Map.empty[String, String])
          }
        } else ("text", "失败:" + ui.toJson, Map.empty[String, String])
      } else{
        val user = new User().queryById(uc.head.uid)
        if (user.isEmpty) {
          new User(uc.head.uid, uc.head.name, uc.head.icon, "", new Date).insertWithId()
          ("text", "插入用户信息成功:" + uc.head.name, Map.empty[String, String])
        }else{
          new User(user.get.id,user.get.name, user.get.icon,user.get.payToken,new Date).update("id","name","icon")
          ("text", "更新用户信息成功:" +  uc.head.name, Map.empty[String, String])
        }
      }
    }
    else
      ("text", "", Map.empty[String, String])

  }

  def getUserBaseInfo(ui: Map[String, String]): (String, String) = {
    val picid = "user/head/" + System.currentTimeMillis().toString
    val icon = if (!ui.isEmpty && !ui.get("headimgurl").isEmpty && !isEmpty(ui("headimgurl"))) {
      Logger.debug(ui("headimgurl"))
      run {
        val headData = NetTool.HttpGetBin(ui("headimgurl"))._2
        fs.saveFile(picid, headData, "image/jpeg")
      }
      fs.getFileUrl(picid.toString())
    } else ""
    val name = ui.getOrElse("nickname", "神秘用户")
    (icon, name)
  }

  def sendredpack(uid: String, token: String, appid: Int)={
    //添加逻辑,是否需要发送红包
    val app=new App().queryById(appid)
    if(app.isDefined) {
      val userToken = new UserConnect().query(s"uid=? and appid=$appid", uid).map(_.token).headOption.getOrElse("")
      val id = uuid.take(15)
      val amount = setting("amount").split("-").map(_.toInt * 100)
      val money = if (amount(0) == amount(1)) amount(0) else Random.nextInt(amount(1) - amount(0)) + amount(0)
      //获取每日限额
      val dateKey=new Date().sdate
      val appDayMoney=JedisTool.useJedis(_.get(APP_DAY_MONEY_KEY+dateKey+"_"+appid).getOrElse("0")).toInt
      val appAllMoney=JedisTool.useJedis(v=>v.get(APP_ALL_MONEY_KEY+"_"+appid).getOrElse{
        v.set(APP_ALL_MONEY_KEY+"_"+appid,app.get.allMoney.toString)
        app.get.allMoney.toString
      }).toInt
      if(appDayMoney+money > app.map(_.dayLimit*100).get ||appAllMoney+money > app.map(_.allLimit*100).get ){ //达到限额，不发红包了
        getWeiXin(appid).sendMsg(userToken, "今日红包已经发完。")
        false
      }else {
        new Order(id, uid, appid, setting("hbname"), money, 0, new Date()).insertWithId()
        val appName = new App().queryById(appid).map(_.name).getOrElse("神秘商家")
        val result = wxRedpack(setting("hbwishing"), appName, setting("hbname"), "点击领取现金红包", money, token, id, setting("ip"))
        Logger.info(result.toJson)
        val str = result.get("return_msg").getOrElse("")
        if (result.get("return_msg").isDefined && result.get("return_msg").get!="发放成功") {
          if (str.contains("余额不足")) {
            getWeiXin(appid).sendMsg(userToken, "今日红包已经发完")
          } else {
            getWeiXin(appid).sendMsg(userToken, "微信限制,无法发送红包")
          }
          new Order(id, status = 2,remark = setting("hbname")+str).update("id", "status","remark")
          false
        } else {
          new Order(id, status = 1,remark = setting("hbname")+str).update("id", "status","remark")
          DBEntity.sql(s"update ${app.get.tableName} set allMoney=allMoney+${money} where id="+appid)
          JedisTool.useJedis(_.incrby(APP_DAY_MONEY_KEY+dateKey+"_"+appid,money))
          JedisTool.useJedis(_.incrby(APP_ALL_MONEY_KEY+"_"+appid,money))
          true
        }
      }
    }else false

  }


  //处理自动登录
  def dealAutoLogin(code: String, uid: Option[String], app: App, isPay: Boolean) = {
    val (id, key) = if (!isPay) (app.appid, app.appsecr) else (setting("weixinAppid"), setting("weixinSecret"))
    val v = NetTool.HttpGet(s"https://api.weixin.qq.com/sns/oauth2/access_token?appid=${id}&secret=${key}&code=${code}&grant_type=authorization_code")
    Logger.debug(v._2)
    if (v._2.contains("{")) {
      val map = SJSON.parseFull(v._2).getOrElse(Map("" -> "")).asInstanceOf[Map[String, AnyRef]]
      val openid = map.getOrElse("openid", "").toString()
      if (uid.isDefined && !isEmpty(openid)) {
        Logger.info("auto login to pay ok!,sendpack")
        //第四步
        val user = new User().queryById(uid.get)
        new User(uid.get, payToken = openid).update("id", "payToken")
        onlyTask("only_"+uid.get) {
          new UserConnect().query("uid=?", uid.get).filter(!_.hasSend).foreach { app =>
            if(sendredpack(uid.get, openid, app.appid)) {
              new UserConnect(app.id, hasSend = true).update("id", "hasSend")
            }
          }
        }
        user
      } else {
        Logger.info("auto login to app ok!,get user info:" + app.id)
        //第二步
        val userData = getWeiXin(app.id).userInfo(openid)
        val unionid = userData.getOrElse("unionid", "").toString()
        if (!isEmpty(unionid)) {
          val user = new User().queryById(unionid)
          if (user.isEmpty) {
            val (icon: String, name: String) = getUserBaseInfo(userData)
            val u = new User(unionid, name, icon, openid, new Date)
            u.insertWithId()
            Some(u)
          } else {
            user
          }
        } else None
      }
    } else None
  }


  /**
    * 微信首页自动登录回调
    *
    * @return
    */
  def index(path: String) = Action.async {
    implicit request =>
      val ret = Assets.at("/public", "ok.html").apply(request).map(_.withHeaders("Cache-Control" -> "no-cache"))
      val List(code, app,uid) = getQuery("code", "app","uid")
      val sessionApp = request.session.get("app")
      val sessionUid = request.session.get("uid")
      val step = if(isEmpty(uid)) request.session.get("step").getOrElse("1").toInt else{ //如果带有uid进来,直接跳转第三部
          val v=request.session.get("step").getOrElse("1").toInt
        if(v<3) 3 else v
      }
      Logger.info(request.uri + " req info app:" + sessionApp.getOrElse("") + ",uid:" + sessionUid.getOrElse("") + ",step:" + step)
      if (step == 4 && app == sessionApp.getOrElse("none")) {
        ret
      } else if (code.isEmpty) {
        if (step < 2  || (sessionUid.isEmpty && isEmpty(uid))) {
          //session中没有app信息,授权获取(第一步)
          if (app.isEmpty) {
            //兼容性处理,没有app信息直接取一个
            Future {
              val suapp = new App().queryAll().head
              Logger.info(request.uri + "no app ,random one:" + suapp.name + "," + suapp.id)
              Redirect(getWeiXin(suapp.id).getAutoMenuUrl(baseUrl + request.path)).withSession(("app", suapp.id), ("step", "2"))
            }
          } else {
            Future {
              Logger.info(request.uri + "auto login app:" + app)
              Redirect(getWeiXin(app).getAutoMenuUrl(baseUrl + request.path)).withSession(("app", app), ("step", "2"))
            }
          }
        } else {
          //有sesionapp,直接跳转支付号授权(订阅号会直接进来)
          Future {
            Logger.info(request.uri + "get user info with uid, auto login to pay app:" + sessionApp.getOrElse(app))
            val u=new User().queryById(if(isEmpty(uid)) sessionUid.get else uid.decrypt() ).dbCheck
            Redirect(weixinPay.getAutoMenuUrl(baseUrl + request.path)).withSession(request.session +("step", "3")+("user", u.toJson.encrypt) +("username", u.name) +("uid", u.id)+("app", app))
          }
        }
      } else {
        val user = dealAutoLogin(code, sessionUid, new App().queryById(if (!sessionApp.isEmpty) sessionApp.get.toInt else if (!isEmpty(app)) app.toInt else 0).getOrElse(null), step>2)
        if (user.isDefined) {
          val u = user.get
          if (step < 3) {
            //保存用户信息并且到服务号授权第三部)
            Future {
              Logger.info(request.uri + "get user info, auto login to pay app:" + sessionApp.get)
              Redirect(weixinPay.getAutoMenuUrl(baseUrl + request.path)).withSession(request.session +("user", u.toJson.encrypt) +("username", u.name) +("uid", u.id) +("step", "3"))
            }
          } else {
            //第四部,最终目的地
            Logger.info(request.uri + "auto login pay ok:" + sessionApp.get)
            ret.map(_.withSession(request.session +("step", "4")))
          }
        } else {
          //没有用户信息,强制授权
          if (app.isEmpty) {
            //没有app信息直接取一个
            Future {
              val suapp = new App().queryAll().head
              Logger.info(request.uri + "auto login fail ,su random one:" + suapp.name + "," + suapp.id)
              Redirect(getWeiXin(suapp.id).getAutoMenuUrl(baseUrl + request.path)).withSession(request.session +("app", suapp.id))
            }
          } else {
            Future {
              Logger.info(request.uri + "auto login fail,su auto login app:" + app)
              Redirect(getWeiXin(app).getAutoMenuUrl(baseUrl + request.path)).withSession(request.session +("app", app))
            }
          }
        }
      }
  }


  def wxRedpack(title: String, sendName: String, actName: String, desc: String, amount: Int, openid: String, orderid: String, ip: String, wx: WeiXin = null) = {
    val params = (if (wx != null) wx else weixinPay).redpackWxPay(title, sendName, actName, desc, orderid, amount, ip, openid)
    val xml =s"""<xml>${params.map(kv => s"<${kv._1}>${kv._2}</${kv._1}>").mkString("\r\n")}</xml>"""
    println(xml)
    val entity = new StringEntity(xml, ContentType.create("text/xml", "utf-8"))
    val v: String = (if (wx != null) wx else weixinPay).certHttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack", entity = entity)
    Logger.info(v)
    val parsexml = scala.xml.XML.loadString(v)
    val data = parsexml.child.map(v => v.label -> v.text).filter(!_._2.trim.isEmpty).toMap
    data
  }


  /**
    * //   * 微信网页签名
    * //    *
    * //    * @return
    * //   */
  //  def jsToken = JsAction {
  //    implicit request =>
  //      val List(url) = getQuery("url")
  //      val data = weixin.JsSignature(url)
  //      Ok(Map("code" -> 200, "msg" -> "成功", "bean" -> data).toJson)
  //  }



  def getJsToken(app:String)=Action.async {
    Future {
      val token=new App().query("appid=?",app).map(v=>getWeiXin(v.id).getJsToken()).headOption.getOrElse("nocode")
      Ok(token)
    }
  }
  def getToken(app:String)=Action.async {
    Future {
      val token=new App().query("appid=?",app).map(v=>getWeiXin(v.id).getToken()).headOption.getOrElse("nocode")
      Ok(token)
    }
  }
}
